library Pk initializer Init requires utils
    globals
        private constant integer PK_UNIT_FLAG_ID = 'h000'
        private constant integer PK_TIME_WAIT = 5
        private constant real PK_REGIN = 1200
    endglobals

    /*
    --------------------------------------------------------------------------
    # PkUnit
    --------------------------------------------------------------------------
    * param 
    */
    struct PkUnit extends array
        delegate Unit m_ud

        timer m_timer

        boolean m_isBeyondRegin
        boolean m_isPking

        static method get takes unit u returns thistype
            local thistype this = thistype(Unit.get(u))

            if m_ud == 0 then
                set this.m_ud = Unit.get(u)
                set this.m_isBeyondRegin = false
                set this.m_isPking = false
            endif

            return this
        endmethod

        method getTimer takes nothing returns timer
            if this.m_timer == null then
                set this.m_timer = NewTimer()
                call SetTimerData(this.m_timer, this)
            endif
            return this.m_timer
        endmethod

        method destroy takes nothing returns nothing
            if this.m_timer != null then
                call ReleaseTimer(this.m_timer)
                set this.m_timer = null
            endif
        endmethod

    endstruct


    /*
    --------------------------------------------------------------------------
    # Pk
    --------------------------------------------------------------------------
    * param 
    */
    struct Pk
        timer m_timer
        unit m_flag
        effect m_effect
        integer m_count

        boolean m_isCancel

        PkUnit m_pkua
        PkUnit m_pkub
        PkUnit m_winner

        implement StructList

        static method get takes PkUnit pkud returns thistype
            local thistype d = thistype.first
            loop
                exitwhen (d <= 0)
                if d.m_pkua == pkud or d.m_pkub == pkud then
                    return d
                endif
                set d = d.next
            endloop
            return 0
        endmethod

        static method create takes unit ua, unit ub returns Pk
            local Pk this = Pk.allocate()
            set this.m_pkua = PkUnit.get(ua)
            set this.m_pkub = PkUnit.get(ub)

            debug call BJDebugMsg("create Pk : " + I2S(this) +"ua :"+GetUnitName(ua)+"ub :"+GetUnitName(ub))

            set this.m_isCancel = false
            set this.m_winner = 0
            set this.m_count = PK_TIME_WAIT
            call this.listAdd()
            return this
        endmethod

        method destroy takes nothing returns nothing
            call this.m_pkua.destroy()
            call this.m_pkub.destroy()

            if m_timer != null then
                call ReleaseTimer(this.m_timer)
                set this.m_timer = null
            endif

            if m_flag != null then
                call RemoveUnit(this.m_flag)
                set this.m_flag = null
            endif

            if m_effect != null then
                call DestroyEffect(this.m_effect)
                set this.m_effect = null
            endif
            
            call this.listRemove()
            call this.deallocate()
        endmethod

        method getTimer takes nothing returns timer
            if this.m_timer == null then
                set this.m_timer = NewTimer()
                call SetTimerData(this.m_timer, this)
            endif
            return this.m_timer
        endmethod

        method setWinner takes PkUnit pkud returns nothing
            set this.m_winner = pkud
        endmethod

        method getOpponent takes PkUnit pku returns PkUnit
            if pku == this.m_pkua then
                set pku = this.m_pkua
            elseif pku == this.m_pkub then
                set pku = this.m_pkub
            endif
            return pku
        endmethod

        method cancel takes nothing returns nothing
            local unit ua = this.m_pkua.m_unit
            local unit ub = this.m_pkub.m_unit

            set this.m_pkua.m_isPking = false
            set this.m_pkub.m_isPking = false
            set this.m_isCancel = true
            
            call DisplayTimedTextToPlayer(GetOwningPlayer(ua), 0, 0, 0.1, "|cffffd700决斗结束|r")
            call DisplayTimedTextToPlayer(GetOwningPlayer(ub), 0, 0, 0.1, "|cffffd700决斗结束|r")

            call this.destroy()
            set ua = null
            set ub = null
        endmethod

        private method setNormalReviveEnable takes boolean isEnable returns nothing
            local Revive reviveA = Revive.get(this.m_pkua.m_ud)
            local Revive reviveB = Revive.get(this.m_pkub.m_ud)

            debug call BJDebugMsg("Revive A:" + I2S(reviveA) + "Revive B:" + I2S(reviveB))

            if reviveA > 0 then
                set reviveA.m_isEnable = isEnable
            endif
            if reviveB > 0 then
                set reviveB.m_isEnable = isEnable
            endif
        endmethod

        method end takes nothing returns nothing
            local PkUnit winner = this.m_winner
            local PkUnit loser = this.getOpponent(winner)
            local unit winneru = winner.m_unit
            local unit loseru = loser.m_unit
            local string text

            call IssueImmediateOrderById(winneru, ORDER_NOTARG_STOP)
            call IssueImmediateOrderById(loseru, ORDER_NOTARG_STOP)
            call SetUnitAlliance(loseru, winneru, true)

            //恢复正常复活方式
            call setNormalReviveEnable(true)

            set text = GetUnitName(loseru) + "在决斗中输给了" + GetUnitName(winneru)
            call DisplayTimedTextToForce(bj_FORCE_ALL_PLAYERS, 3.00, text)

            call this.cancel()
            set winneru = null
            set loseru = null
            set text = null
        endmethod

        private static method anon_bb1eea12 takes nothing returns nothing  //暂停正常复活方式
            local Pk this = GetTimerData(GetExpiredTimer())
            call this.setWinner(this.m_pkub)
            call this.end()
        endmethod

        private static method anon_7f4d7083 takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            call this.setWinner(this.m_pkua)
            call this.end()
        endmethod

        private static method anon_6fd9ebf83d6f takes nothing returns nothing
            local Pk this = GetTimerData(GetExpiredTimer())
            local unit ua = this.m_pkua.m_unit
            local unit ub = this.m_pkub.m_unit
            local real disS = GetDistanceByUnitXY(ua, this.m_flag)
            local real disA = GetDistanceByUnitXY(ub, this.m_flag)
            local string strA = "|cffffd700已返回决斗区域，继续决斗|"
            local string strB = "|cffffd700已脱离决斗区域，如果不马上返回，10秒后系统将判定为输|r"

            if disS <= PK_REGIN and this.m_pkua.m_isBeyondRegin then

                set this.m_pkua.m_isBeyondRegin = false
                call PauseTimer(this.m_pkua.getTimer())
                
                call DisplayTimedTextToPlayer(GetOwningPlayer(ua), 0, 0, 1.0, strA)

            elseif disS > PK_REGIN and not (this.m_pkua.m_isBeyondRegin) then

                set this.m_pkua.m_isBeyondRegin = true
                call DisplayTimedTextToPlayer(GetOwningPlayer(ua), 0, 0, 1.0, strB)
                call TimerStart(this.m_pkua.getTimer(), 10.00, false, function thistype.anon_bb1eea12)

            endif

            if disA <= PK_REGIN and this.m_pkub.m_isBeyondRegin then

                set this.m_pkub.m_isBeyondRegin = false
                call PauseTimer(this.m_pkub.getTimer())
                call DisplayTimedTextToPlayer(GetOwningPlayer(ub), 0, 0, 1.0, strA)

            elseif disA > PK_REGIN and not (this.m_pkub.m_isBeyondRegin) then

                set this.m_pkub.m_isBeyondRegin = true
                call DisplayTimedTextToPlayer(GetOwningPlayer(ub), 0, 0, 1.0, strB)
                call TimerStart(this.m_pkub.getTimer(), 10.00, false, function thistype.anon_7f4d7083)
            endif

            set ua = null
            set ub = null
        endmethod

        private static method anon_cd1db33d0115 takes nothing returns nothing
            local Pk this = GetTimerData(GetExpiredTimer())
            local unit ua = this.m_pkua.m_unit
            local unit ub = this.m_pkub.m_unit
            local string path

            if this.m_count > 0 then
                set this.m_count = this.m_count - 1

                //call CommonUtils.showSizedTexttagOnUnit(this.m_flag, I2S(this.m_count), null, 10.00, 2.00)

                if this.m_count == PK_TIME_WAIT then
                    set path = "Units\\Orc\\HealingWard\\PlaceAncestralGuardian.wav"

                    call RunSoundOnUnit(NewSound(path, 1500, false, true), this.m_flag)
                endif

                set path = "Sound\\Interface\\BattleNetTick.wav"
                call RunSoundOnUnit(NewSound(path, 476, false, true), this.m_flag)
            else
                //call CommonUtils.showSizedTexttagOnUnit(this.m_flag, "|cffffd700开始|r", null, 10.00, 2.00)

                set path = "Units\\Orc\\Cairne\\CairneYesAttack3.wav"
                call RunSoundOnUnit(NewSound(path, 766, false, true), this.m_flag)

                set path = "Abilities\\Spells\\Items\\AIlm\\AIlmTarget.mdl"
                call AddEffectTarget(path, ua, "origin")
                call AddEffectTarget(path, ub, "origin")
                call SetUnitAlliance(ua, ub, false)
                call setNormalReviveEnable(false)

                call TimerStart(this.getTimer(), 0.50, true, function thistype.anon_6fd9ebf83d6f)
            endif

            set path = null
            set ua = null
            set ub = null
        endmethod

        method begin takes nothing returns nothing
            local unit ua = this.m_pkua.m_unit
            local unit ub = this.m_pkub.m_unit
            local real x = (GetUnitX(ua) + GetUnitX(ub)) / 2.00
            local real y = (GetUnitY(ua) + GetUnitY(ub)) / 2.00
            local string path

            set this.m_pkua.m_isPking = true
            set this.m_pkub.m_isPking = true

            set this.m_flag = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), PK_UNIT_FLAG_ID, x, y, 0)
            set path = "Objects\\InventoryItems\\BattleStandard\\BattleStandard.mdl"
            set this.m_effect = AddSpecialEffectTarget(path, this.m_flag, "origin")

            call SetUnitScale(this.m_flag, 1.50, 1.50, 1.50)
            call SetUnitFlyHeight(this.m_flag, 300.00, 0.00)
            call SetUnitFlyHeight(this.m_flag, 0.00, 300.00)
            //call CommonUtils.showSizedTexttagOnUnit(this.m_flag, "|cffffd700决斗倒计时|r", null, 10.00, 2.00)
            call TimerStart(this.getTimer(), 1.00, true, function thistype.anon_cd1db33d0115)

            set path = null
            set ua = null
            set ub = null
        endmethod

    endstruct

    /*
    --------------------------------------------------------------------------
    # PkUnitDeath EVENT
    --------------------------------------------------------------------------
    * param 
    */

    private function PkUnitDeath takes unit u returns nothing
        local PkUnit pku = PkUnit.get(u)
        local Pk pk

        if pku.m_isPking then
            set pk = Pk.get(pku)

            call ReviveHero(u, GetUnitX(u), GetUnitY(u), false)

            call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_MAX_LIFE) * 0.02)
            call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MAX_MANA) * 0.02)
            
            call SelectUnitForPlayerSingle(u, GetOwningPlayer(u))  // 限时2秒无敌
            call UnitUtils.setUnitInvulnerableTimed(u, 2.00)

            call pk.setWinner(pk.getOpponent(pku))
            call pk.end()
        endif
    endfunction

    private function Init takes nothing returns nothing
        call RegisterUnitDeathResponse(PkUnitDeath)
    endfunction

endlibrary